
package com.jimo.qrcode.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.jimo.qrcode.dto.QRCodeDto;
import com.jimo.qrcode.dto.QRCodeLogoDto;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Hashtable;

/**
 * Title: QRCodeUtils
 * Description: 二维码工具类
 * @author JIMO
 * @date 2019年4月28日
 */
public class QRCodeUtils {

    public static BufferedImage createImage(QRCodeDto dto) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, dto.getErrorCorrection());
        hints.put(EncodeHintType.CHARACTER_SET, dto.getCharset());
        hints.put(EncodeHintType.MARGIN, dto.getMargin());
        BitMatrix bitMatrix = new MultiFormatWriter().encode(dto.getContent(), BarcodeFormat.QR_CODE, dto.getSize(), dto.getSize(),
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? dto.getColor() : dto.getBackgroundColor());
            }
        }
        if (ObjectUtils.isEmpty(dto.getLogo()) || ObjectUtils.isEmpty(dto.getLogo().getPath())) {
            return image;
        }
        // 插入图片
        insertImage(image, dto);
        return image;
    }
    
    private static void insertImage(BufferedImage source, QRCodeDto dto) throws IOException {
        InputStream inputStream = null;
        try {
        	QRCodeLogoDto logo = dto.getLogo();
            inputStream = FileUtils.getResourceAsStream(logo.getPath());
            Image src = ImageIO.read(inputStream);
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            if (logo.isNeedCompress()) {
                // 压缩LOGO
                if (width > logo.getWidth()) {
                    width = logo.getWidth();
                }
                if (height > logo.getHeight()) {
                    height = logo.getHeight();
                }
                Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                // 绘制缩小后的图
                g.drawImage(image, 0, 0, null);
                g.dispose();
                src = image;
            }
            // 插入LOGO
            Graphics2D graph = source.createGraphics();
            int x = (dto.getSize() - width) / 2;
            int y = (dto.getSize() - height) / 2;
            graph.drawImage(src, x, y, width, height, null);
            Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
            graph.setStroke(new BasicStroke(3f));
            graph.draw(shape);
            graph.dispose();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }
    
    /**
     * 
     * Title: encode
     * Description: 生成二维码
     * @param dto 二维码生成规则
     * @return 返回二维码名（不包含其所在文件夹的地址）
     * @throws Exception
     */
    public static String encode(QRCodeDto dto) throws Exception {
    	BufferedImage image = createImage(dto);
        mkdirs(dto.getDestPath());
        String fileName = dto.getFileName();
        if (ObjectUtils.isEmpty(fileName)) {
            fileName = (new Date()).getTime() + "." + dto.getFormat();
        }
        ImageIO.write(image, dto.getFormat(), new File(dto.getDestPath() + "/" + fileName));
        return fileName;
    }
    
    /**
     * 
     * Title: encode
     * Description: 生成二维码
     * @param dto 二维码生成规则
     * @param output 输出流
     * @throws Exception
     */
    public static void encode(QRCodeDto dto, OutputStream output)
            throws Exception {
        BufferedImage image = createImage(dto);
        ImageIO.write(image, dto.getFormat(), output);
    }

    /**
     * 当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir．
     * (mkdir如果父目录不存在则会抛出异常)
     *
     * @param destPath 存放目录
     */
    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

}
